#include "jeremy.h"

/* Maximalni delka http hlavicky */
#define MAX_HTTP_HEADER_LEN 32768

/* Maximalni delka jmena souboru, ktery je klientem pozadovan */
#define MAX_FILENAME_LEN 32768

/* Nacteni http hlavicek od klienta */
int http_read_headers(struct main_structure * jeremy, struct settings * headers, struct settings * nastaveni)
{
	char * line;
	char * header_name;
	char * header_value;

	/* Rekneme si o pamet pro nacteni radky */
	line = (char *) malloc(MAX_HTTP_HEADER_LEN);
	if (line == NULL) {
		if (DEBUG == true) {
			puts("Nelze alokovat operacni pamet!");
		}

		return false;
	}

	/* Rekneme si o pamet pro nacteni jmena hlavicky */
	header_name = (char *) malloc(MAX_HTTP_HEADER_LEN);
	if (header_name == NULL) {
		if (DEBUG == true) {
			puts("Nelze alokovat operacni pamet!");
		}

		return false;
	}

	/* Rekneme si o pamet pro nacteni hodnoty hlavicky */
	header_value = (char *) malloc(MAX_HTTP_HEADER_LEN);
	if (header_value == NULL) {
		if (DEBUG == true) {
			puts("Nelze alokovat operacni pamet!");
		}

		return false;
	}

	while(http_read_header_line(jeremy->client_fd, line, MAX_HTTP_HEADER_LEN) == true) {

		/* Znak '\r' na teto pozici => jedna se o ukonceni http dotazu od klienta */
		if (line[0] == '\r') {
			if (DEBUG == true) {
				puts("Nactena radka ukoncujici http zadost.");
				break;
			}
		}

		/* Zjistime jmeno a hodnotu hlavicky */
		http_header_get_name(line, header_name);
		http_header_get_value(line, header_value);

		if (DEBUG == true) {
			printf("Jmeno nactene hlavicky: #%s#\n", header_name);
			printf("Hodnota nactene hlavicky: #%s#\n", header_value);
		}

		/* Vlozime novou http hlavicku */
		add_settings(headers, header_name, header_value);
	}

	/* Uvolnime alokovanou pamet */
	free(line);
	free(header_name);
	free(header_value);

	return true;
}

/* Budeme z daneho deskriptoru cist, dokud nenarazime na '\n' 
 * Vraci true, ale v priapde, ze bude prekrocen max_res_len tak vrati false */
int http_read_header_line(int fd, char * result, int max_res_len)
{
	int b;
	char buf;
	int i;

	i = 0;

	/* Cteni bajt po bajtu dokud nedojde k chybe */
	while((b = read(fd, (char *) &buf, 1) != -1)) {
		
		/* Pokud nebylo nic nacteno nebo byl nacten '\n', koncime se ctenim */
		if (b == 0 || buf == '\n') break;

		/* Pokud byl prekrocen maximalni limit nactenych bajtu, tak koncime a vratime false */
		if ((i - 1) == max_res_len) {
			*(result + i) = '\0';
			return false;
		}

		*(result + i) = buf;
		i++;
	}

	/* Ukoncime string */
	*(result + i) = '\0';

	return true;
} 

/* Nacte jmeno http hlavicky - nacita zleva az do prvni mezery, vraci true, v pripade chyby vraci false */
int http_header_get_name(char * line, char * header_name)
{
	int i;

	for(i = 0; *(line + i) != ' '; i++) {

		/* V pripade chyby vratime false */
		if (*(line + i) == '\0' || *(line + i) == '\r') {
			return false;
		}
		
		*(header_name + i) = *(line + i);
	}

	*(header_name + i) = '\0';
	return true;
}

/* Nacte hodnotu http hlavicky - jede od prvni mezery az do ukonceni stringu, vraci true, v pripade chyby vraci false */
int http_header_get_value(char * line, char * header_value)
{
	int i;
	int i2;

	/* Posuneme se za prvni mezeru zleva */
	for(i = 0; *(line + i) != ' '; i++) {
		;
	}
	i++;

	/* Zkopirujeme cast za prvni mezerou zleva */
	for(i2 = 0; *(line + i) != '\r'; i++, i2++) {
		
		if (*(line + i) == '\0') break;

		*(header_value + i2) = *(line + i);
	}

	*(header_value + i2) = '\0';

	return true;
}

/* Kontrola minimalniho mnozstvi http hlavicek podle rfc
 * vraci true, v pripade chyby vraci false */
int http_check_min_headers(struct main_structure * jeremy, struct settings * headers)
{
	struct settings * main_request;
	struct settings * host;

	main_request = get_settings(headers, "GET");
	if (main_request == NULL) {
		main_request = get_settings(headers, "POST");
	}

	host = get_settings(headers, "Host:");

	if (main_request == NULL || host == NULL) {
		return false;
	}

	return true;
}

/* Prida do struktury jeremyho jmeno pozadovenho souboru
 * vraci true, v pripade chyby vraci false */
int http_requested_filename(struct main_structure * jeremy, struct settings * headers)
{
	struct settings * first_header;
	char * requested_filename;
	int i;

	first_header = get_settings(headers, "GET");
	if (first_header == NULL) {
		first_header = get_settings(headers, "POST");
	}

	if (first_header == NULL) {
		if (DEBUG == true) {
			printf("Nepodarilo se najit zakladni hlavicku.");
		}

		return false;
	}

	/* Jmeno souboru je hodnota hlavicky az do prvniho otazniku popripade mezery(v pripade, ze nebyl poslan zadny query string
	 * v pripade, ze string zkonci pred prvni mezerou, tak se jedna o chybu (nebyl poslan protokol) tak vracime false */
	requested_filename = (char *) malloc(MAX_FILENAME_LEN);
	if (requested_filename == NULL) {
		if (DEBUG == true) {
			printf("Nelze alokovat operacni pamet!\n");
		}

		return false;
	}

	for(i = 0; *(first_header->value + i) != ' ' && *(first_header->value + i) != '?'; i++) {

		/* Nejdrive je nutne osetrit patologicke znaky, ktere zpusobi chybu */
		if (*(first_header->value + i) == '\r' || *(first_header->value + i) == '\n' || *(first_header->value + i) == '\0') {
			if (DEBUG == true) {
				printf("Spatne jmeno souboru poslano klientem.\n");
			}

			return false;
		}

		/* Nyni lze zkopirovat znak */
		*(requested_filename + i) = *(first_header->value + i);
	}

	*(requested_filename + i) = '\0';
	jeremy->requested_filename = requested_filename;
	return true;
}

/* Prida do struktury jeremyho query string poslany v pozadovanem url
 * vraci true, v pripade chyby vraci false */
int http_requested_query_string(struct main_structure * jeremy, struct settings * headers)
{

}
